/*
 * Copyright (C) 2006-2012 TongYan Corporation
 * All rights reserved.
 *
 * @brief info:
 *
 * @author: 王哲成 - wangzhecheng@yeah.net
 * @date: 2021.05.20
 * @last modified: 2021-05-20 11:16
 *
 */

#ifndef __ISG_TARGET_FUNCTION_HEADER__
#define __ISG_TARGET_FUNCTION_HEADER__

#include "Param.hpp"
#include <algorithm>
#include <vector>

class ISGObjectFunction {
public:
  ISGObjectFunction() = default;
  virtual ~ISGObjectFunction() = default;

  // 计算目标函数在参数向量x处的值
  virtual double functionValue(const Vector &x) const = 0;
  // 计算雅可比向量Jx（梯度向量）
  virtual Vector gradientVector(const Vector &x,
                                const Vector &dx = Vector{}) const;
  // 用二阶导数计算海瑟矩阵Hx
  virtual Matrix HessianMatrix(const Vector &x,
                               const Vector &dx = Vector{}) const;
  // 问题是否是最小二乘问题
  virtual bool ifLeastSquareProblem() const { return true; }

private:
  // 中心差分法得一阶偏微分
  double firstDeriv(const Vector &x, const size_t &loc,
                    const double &delta) const;
  // 中心差分法得二阶偏微分(对同一变量两次求偏导)
  double secondDeriv(const Vector &x, const size_t &loc,
                     const double &delta) const;
  // 中心差分法得二阶偏微分(对不同变量两次求偏导)
  double secondDeriv(const Vector &x, const size_t &loc_x,
                     const double &delta_x, const size_t &loc_y,
                     const double &delta_y) const;
};

class ISGLeastSquareProblem : public ISGObjectFunction {
public:
  // 问题是否是最小二乘问题
  virtual bool ifLeastSquareProblem() const override { return true; }

  // 计算残差函数的雅可比向量Jx(针对最小二乘法问题)
  virtual Vector gradientVector(const Vector &x,
                                const Vector &dx = Vector{}) const override;

  // TODO
  // 计算目标函数在参数向量x处的值
  virtual double functionValue(const Vector &x) const override { return 0; }

  virtual std::vector<double> getValue(const Vector &x) const = 0;

  // 用一阶导数计算海瑟矩阵Hx
  virtual Matrix HessianMatrix(const Vector &x,
                               const Vector &dx = Vector{}) const override;

  virtual double functionValue(const Vector &x, const Point &coord) const {
    return 0;
  }

  private:
  std::vector<std::pair<Point, double>> m_vecObjectValue;
};

#endif
